package com.axend.lib_base.help.otgserial;

import static com.axend.lib_base.help.Constant.MMKV_KEY_RADAR_VERSION;

import android.serialport.SerialPort;
import android.util.Log;

import com.axend.lib_base.bean.RadarUpBean;
import com.axend.lib_base.utils.ByteUtil;
import com.axend.lib_base.utils.MMKVUtil;
import com.axend.lib_base.utils.RadarCRC16;
import com.axend.lib_base.utils.log.MyLogUtils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Queue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * 串口实处理类
 */
public class SerialHandle implements Runnable {

    private static final String TAG = "串口处理类";
    private String path = "";//串口地址
    private SerialPort mSerialPort;//串口对象
    private InputStream mInputStream;//串口的输入流对象
    private BufferedInputStream mBuffInputStream;//用于监听硬件返回的信息
    private OutputStream mOutputStream;//串口的输出流对象 用于发送指令
    private SerialInter serialInter;//串口回调接口
    private ScheduledFuture readTask;//串口读取任务
    private static final int HEART_RATE_BLOCK_SIZE = 256;
    int blockLength = HEART_RATE_BLOCK_SIZE;
    int blockNum;
    byte[][] firmwareData;
    int num_count = 0;
    RadarUpBean radaebean = null;
    private volatile boolean commandSuccess = false;
    private volatile boolean isSucc = false;
    private volatile int offLineCount = 0;
    private volatile int onLineCount=0;
    private Queue<RadarCommand> radarCommandQueue = null;


    /**
     * 添加串口回调
     *
     * @param serialInter
     */
    public void addSerialInter(SerialInter serialInter) {
        this.serialInter = serialInter;
        if (serialInter != null) {
            radaebean = serialInter.writeData();
        }
    }

    /**
     * 打开串口
     *
     * @param devicePath 串口地址(根据平板的说明说填写)
     * @param baudrate   波特率(根据对接的硬件填写 - 硬件说明书上"通讯"中会有标注)
     * @param isRead     是否持续监听串口返回的数据
     * @return 是否打开成功
     */
    public boolean open(String devicePath, int baudrate, boolean isRead) {
        return open(devicePath, baudrate, 8, 1, 0, isRead);
    }

    /**
     * 打开串口
     *
     * @param devicePath 串口地址(根据平板的说明说填写)
     * @param baudrate   波特率(根据对接的硬件填写 - 硬件说明书上"通讯"中会有标注)
     * @param dataBits   数据位(根据对接的硬件填写 - 硬件说明书上"通讯"中会有标注)
     * @param stopBits   停止位(根据对接的硬件填写 - 硬件说明书上"通讯"中会有标注)
     * @param parity     校验位(根据对接的硬件填写 - 硬件说明书上"通讯"中会有标注)
     * @param isRead     是否持续监听串口返回的数据
     * @return 是否打开成功
     */
    public boolean open(String devicePath, int baudrate, int dataBits, int stopBits, int parity, boolean isRead) {
        isSucc = false;
        try {
            if (mSerialPort != null) close();
            File device = new File(devicePath);
            mSerialPort = SerialPort // 串口对象
                    .newBuilder(device, baudrate) // 串口地址地址，波特率
                    .dataBits(dataBits) // 数据位,默认8；可选值为5~8
                    .stopBits(stopBits) // 停止位，默认1；1:1位停止位；2:2位停止位
                    .parity(parity) // 校验位；0:无校验位(NONE，默认)；1:奇校验位(ODD);2:偶校验位(EVEN)
                    .build(); // 打开串口并返回
            path = devicePath;
            if (isRead) {
                mInputStream = mSerialPort.getInputStream();
                mBuffInputStream = new BufferedInputStream(mInputStream);
                mOutputStream = mSerialPort.getOutputStream();
                readData();//开启识别
            }
            isSucc = true;
        } catch (Throwable tr) {
            close();
            isSucc = false;
        } finally {
//            serialInter.connectMsg(devicePath, isSucc);
            return isSucc;
        }
    }

    public boolean isConnect() {
        return isSucc;
    }

    // 读取数据
    private void readData() {
        if (readTask != null) {
            readTask.cancel(true);
            try {
                Thread.sleep(160);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //此处睡眠：当取消任务时 线程池已经执行任务，无法取消，所以等待线程池的任务执行完毕
            readTask = null;
        }
        readTask = SerialManage
                .getInstance()
                .getScheduledExecutor()//获取线程池
                .scheduleAtFixedRate(this, 0, 50, TimeUnit.MILLISECONDS);//执行一个循环任务
    }

    @Override//每隔 50 毫秒会触发一次run
    public void run() {
        if (Thread.currentThread().isInterrupted()) return;
        try {
            int available = mBuffInputStream.available();
            if (available == 0) {
                //离线判断 50ms一次 200次10秒
                offLineCount++;
                if (offLineCount > 200) {
                    onLineCount=0;
                    offLineCount = 0;
                    isSucc = false;
                    serialInter.connectMsg(path, false);
                    return;
                }
                // 处理没有数据可读的情况
                try {
                    Thread.sleep(100); // 防止 CPU 占用过高
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return;
            }
            offLineCount = 0;
            onLineCount++;
            if (onLineCount > 6){
                isSucc = true;
                serialInter.connectMsg(path, true);
                onLineCount=0;
            }
            byte[] received = new byte[1024];
            int size = mBuffInputStream.read(received);//读取以下串口是否有新的数据
            if (size > 0 && serialInter != null) {
                boolean click = serialInter.updata_button_click();
                if (click) {
                    radaebean = serialInter.writeData();
                }
            }

            if (received[15] == 27 || received[15] == 29) {
                if (received[19] == 01) {
                    commandSuccess = true;
                    Log.d(TAG, "radar set success");
                } else if (received[19] == 00) {
                    commandSuccess = false;
                    Log.d(TAG, "radar set failed");
                }
                return;
            }

//            Log.d(TAG, "串口返回数据：" + bytesToHexString(received));
            if ((received[13] == 20) && (!radaebean.getFlag())) {
                byte[] response_data = new byte[]{19, 1, 0, 2, received[4], received[5], received[6], received[7], 0, 0,
                        0, 0, 0, 6, 0, 1, 0, 0, 0, 1};
//                Log.d(TAG, "串口返回数据：" + bytesToHexString(response_data));
                byte[] version_byte = {received[17], received[18], received[19], received[20]};
                if (size > 0 && serialInter != null){
                    /*存储版本号*/
                    MMKVUtil.Companion.getInstance().encode(MMKV_KEY_RADAR_VERSION,byteArrayToCommaSeparatedString(version_byte));
                    serialInter.radarVersion(version_byte);
                }

                try {
                    if ((radarCommandQueue == null || radarCommandQueue.size() == 0) && !radaebean.getReadVersion()) {
                        mOutputStream.write(response_data);  // 写入数据，延迟设置太大的话如果下发间隔太小可能报错
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }

            if (size > 0 && serialInter != null && isSucc) serialInter.readData(path, received, size);

            if (radaebean.getFlag() && ((received[13] == 20) || (received[13] == 38))) {

                firmwareData = splitAndCrc16(radaebean.getFilepath(), blockLength);
                blockNum = firmwareData.length;
                serialInter.progress(0, blockNum);
                int length = radaebean.getFilepath().length;

                byte[] nums2 = ByteUtil.intToByteBig(length);

                byte[] nums1 = new byte[]{19, 1, 0, 2, received[4], received[5], received[6], received[7], 0, 0,
                        0, 0, 0, 6, 0, 33};

                int newArrayLength = nums1.length + nums2.length;
                byte[] mergedArray = new byte[newArrayLength];
                System.arraycopy(nums1, 0, mergedArray, 0, nums1.length);
                System.arraycopy(nums2, 0, mergedArray, nums1.length, nums2.length);
                try {
                    mOutputStream.write(mergedArray);  // 写入数据，延迟设置太大的话如果下发间隔太小可能报错
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // radaebean.setFlag(false);
            }

            if (received[15] == 35) {
                radaebean.setFlag(false);
                serialInter.progress(num_count, blockNum);
                num_count = 0;
                Log.d(this.getClass().getSimpleName(), "finish updata radar model");
            }

            if ((num_count == blockNum) && (num_count > 0)) {
                serialInter.progress(num_count, blockNum);
                num_count = num_count + 1;
                byte[] nums1 = new byte[]{19, 1, 0, 2, received[4], received[5], received[6], received[7], 0, 0,
                        0, 0, 0, 6, 0, 35, 0, 0, 0, 0};

                try {
                    mOutputStream.write(nums1);  // 写入数据，延迟设置太大的话如果下发间隔太小可能报错
//                    System.out.println("1111111111111111");

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if ((received[15] == 33) || (received[15] == 34)) {

                if (num_count < blockNum) {
                    byte[] data = firmwareData[num_count];
                    int all_datalen = data.length + 2;
                    byte[] nums2 = ByteUtil.intToByteBig(all_datalen);

                    byte[] nums1 = new byte[]{19, 1, 0, 2, received[4], received[5], received[6], received[7], 0, 0,
                            nums2[0], nums2[1], nums2[2], nums2[3], 0, 34};

                    int newArrayLength = nums1.length + data.length;
                    byte[] mergedArray = new byte[newArrayLength];
                    System.arraycopy(nums1, 0, mergedArray, 0, nums1.length);
                    System.arraycopy(data, 0, mergedArray, nums1.length, data.length);
                    try {
                        mOutputStream.write(mergedArray);  // 写入数据，延迟设置太大的话如果下发间隔太小可能报错
//                        System.out.println("1111111111111111");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    serialInter.progress(num_count, blockNum);
                    num_count = num_count + 1;


                }


            }
        } catch (Exception e) {
            serialInter.connectMsg(path, false);
            isSucc = false;
            Log.e(TAG, "串口读取数据异常:" + e.toString());
        }
    }

    /**
     * 关闭串口
     */
    public void close() {
        try {
            if (mInputStream != null) mInputStream.close();
        } catch (Exception e) {
            Log.e(TAG, "串口输入流对象关闭异常：" + e.toString());
        }
        try {
            if (mOutputStream != null) mOutputStream.close();
        } catch (Exception e) {
            Log.e(TAG, "串口输出流对象关闭异常：" + e.toString());
        }
        try {
            if (mSerialPort != null) mSerialPort.close();
            mSerialPort = null;
            if (readTask != null) readTask.cancel(true);
            readTask = null;
            num_count = 0;
        } catch (Exception e) {
            Log.e(TAG, "串口对象关闭异常：" + e.toString());
        }
        isSucc = false;
    }

    /**
     * 向串口发送指令
     */
    public void send(final String msg) {
        byte[] bytes = hexStr2bytes(msg);//字符转成byte数组
        try {
            mOutputStream.write(bytes);//通过输出流写入数据
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setHeartFreqHz(Queue<RadarCommand> radarCommandQueue) {
        if (mOutputStream != null) {
            try {
                this.radarCommandQueue = radarCommandQueue;
                RadarCommand radarCommand = radarCommandQueue.peek();
                if (radarCommand != null) {
                    byte[] command = DataSender.getSendData(radarCommand.getTag(), radarCommand.getData());
//                    Log.d(TAG, "send command: " + bytesToHexString(command));
                    mOutputStream.write(command);
                    if (commandSuccess) {
                        commandSuccess = false;
                        radarCommandQueue.poll();
                        if (radarCommandQueue.size() == 0) {
                            /*再下发接收雷达心率、呼吸数据*/
                            /*延迟500毫秒*/
                            Thread.sleep(600);
                            byte[] response_data = new byte[]{19, 1, 0, 2, -101, 0, 0, 0, 0, 0,
                                    0, 0, 0, 6, 0, 1, 0, 0, 0, 1};
                            mOutputStream.write(response_data);
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }


    /**
     * 把十六进制表示的字节数组字符串，转换成十六进制字节数组
     *
     * @param
     * @return byte[]
     */
    private byte[] hexStr2bytes(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toUpperCase().toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (hexChar2byte(achar[pos]) << 4 | hexChar2byte(achar[pos + 1]));
        }
        return result;
    }

    /**
     * 把16进制字符[0123456789abcde]（含大小写）转成字节
     *
     * @param c
     * @return
     */
    private static int hexChar2byte(char c) {
        switch (c) {
            case '0':
                return 0;
            case '1':
                return 1;
            case '2':
                return 2;
            case '3':
                return 3;
            case '4':
                return 4;
            case '5':
                return 5;
            case '6':
                return 6;
            case '7':
                return 7;
            case '8':
                return 8;
            case '9':
                return 9;
            case 'a':
            case 'A':
                return 10;
            case 'b':
            case 'B':
                return 11;
            case 'c':
            case 'C':
                return 12;
            case 'd':
            case 'D':
                return 13;
            case 'e':
            case 'E':
                return 14;
            case 'f':
            case 'F':
                return 15;
            default:
                return -1;
        }
    }

    public byte[][] splitAndCrc16(byte[] firmwareData, int size) {
        int blockSize = (firmwareData.length / size) + (firmwareData.length % size > 0 ? 1 : 0);
        byte[][] splitData = new byte[blockSize][];
        for (int i = 0; i < blockSize; i++) {
            int blockIndex = i + 1;
            int startIndex = i * size;
            int endIndex = blockIndex * size;
            if (endIndex > firmwareData.length) {
                endIndex = firmwareData.length;
            }
            byte[] blockData = Arrays.copyOfRange(firmwareData, startIndex, endIndex);
            int blockCrc16 = RadarCRC16.crc16BaseRadar(blockData);
            byte[] crc16Bytes = ByteUtil.shortToByteLittle((short) blockCrc16);
            boolean attachBlockIndex = false;
            int bytesLength = attachBlockIndex ? blockData.length + 4 + 2 : blockData.length + 2;
            byte[] bytes = new byte[bytesLength];
            int copyStartIndex = 0;
            if (attachBlockIndex) {
                //雷达升级包索引序号从0开始
                byte[] blockIndexBytes = ByteUtil.intToByteBig(blockIndex - 1);
                System.arraycopy(blockIndexBytes, 0, bytes, copyStartIndex, 4);
                copyStartIndex += 4;
            }
            System.arraycopy(blockData, 0, bytes, copyStartIndex, blockData.length);
            copyStartIndex += blockData.length;
            System.arraycopy(crc16Bytes, 0, bytes, copyStartIndex, 2);
            splitData[i] = bytes;
        }
        return splitData;
    }


    /**
     * byte数组转16进制格式的字符串
     *
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString().toUpperCase();
    }

    public static String byteArrayToCommaSeparatedString(byte[] byteArray) {
        StringBuilder sb = new StringBuilder();
        for (byte b : byteArray) {
            if (sb.length() > 0) {
                sb.append("."); // 添加分隔符
            }
            sb.append(b); // 将字节转换为字符串
        }
        return sb.toString();
    }

}
